package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.Timer;

import main.IAgentListener;
import main.LabyrinthControl;
import agent.IAgent;

/**
 * The main control panel on the left hand side of the main window
 * 
 * @author Johannes Kulick
 * @version 1.0beta1
 * @licence GNU Lesser Genaral Public Licence
 */
public class ControlPanel extends JPanel implements ActionListener,
		IAgentListener {
	private static final long serialVersionUID = -4483465162904548501L;

	private LabyrinthControl mControl;

	private IAgent mAgent;

	private JTextField mSteps;

	private JTextField mTime;

	private long mNumSteps = 0;

	private long mNumSecs = 0;

	private Timer mTimer;

	private JComboBox mAgentsBox;

	/**
	 * Standard constructor
	 * 
	 * @param control
	 *            The Labyrinth this ControlPanel should remote
	 */
	public ControlPanel(LabyrinthControl control) {
		super();

		mControl = control;

		// Add the Buttons, Labels etc.
		JButton start = new JButton("Start");
		start.setActionCommand("start");
		start.addActionListener(this);

		JButton stop = new JButton("Stop");
		stop.setActionCommand("stop");
		stop.addActionListener(this);

		JLabel stepsLabel = new JLabel("Schritte:");
		mSteps = new JTextField("0");
		mSteps.setHorizontalAlignment(JTextField.RIGHT);

		JLabel timeLabel = new JLabel("Zeit:");
		mTime = new JTextField("00:00:00.0");
		mTime.setHorizontalAlignment(JTextField.RIGHT);

		JButton newLab = new JButton("Neues Labyrinth");
		newLab.setActionCommand("new");
		newLab.addActionListener(this);

		JLabel agentLabel = new JLabel("Agenten:");
		mAgentsBox = new JComboBox(mControl.getPossibleAgents().toArray());
		mAgentsBox.setActionCommand("agent");
		mAgentsBox.addActionListener(this);

		JButton rmAgent = new JButton("Entferne Agent");
		rmAgent.setActionCommand("rm");
		rmAgent.addActionListener(this);

		JButton addAgent = new JButton("Lade Agent");
		addAgent.setActionCommand("add");
		addAgent.addActionListener(this);

		// layoutmanagement...
		GroupLayout layout = new GroupLayout(this);
		setLayout(layout);

		layout.setVerticalGroup(layout.createSequentialGroup().addGroup(
				layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
						.addComponent(start).addComponent(stop)).addComponent(
				agentLabel).addComponent(mAgentsBox,
				GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE,
				GroupLayout.PREFERRED_SIZE).addGroup(
				layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
						.addComponent(timeLabel).addComponent(mTime)).addGroup(
				layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
						.addComponent(stepsLabel).addComponent(mSteps))
				.addComponent(newLab).addGroup(
						layout.createParallelGroup(
								GroupLayout.Alignment.BASELINE).addComponent(
								addAgent).addComponent(rmAgent)));
		layout.linkSize(SwingConstants.HORIZONTAL, start, stop, addAgent,
				rmAgent);
		layout.linkSize(SwingConstants.HORIZONTAL, stepsLabel, timeLabel);

		layout.setHorizontalGroup(layout.createParallelGroup(
				GroupLayout.Alignment.LEADING).addGroup(
				layout.createSequentialGroup().addComponent(start,
						GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE,
						Short.MAX_VALUE).addComponent(stop,
						GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE,
						Short.MAX_VALUE)).addComponent(agentLabel)
				.addComponent(mAgentsBox, GroupLayout.DEFAULT_SIZE,
						GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addGroup(
						layout.createSequentialGroup().addComponent(timeLabel)
								.addComponent(mTime, GroupLayout.DEFAULT_SIZE,
										GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE)).addGroup(
						layout.createSequentialGroup().addComponent(stepsLabel)
								.addComponent(mSteps, GroupLayout.DEFAULT_SIZE,
										GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE)).addComponent(newLab,
						GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE,
						Short.MAX_VALUE).addGroup(
						layout.createSequentialGroup().addComponent(addAgent,
								GroupLayout.DEFAULT_SIZE,
								GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
								.addComponent(rmAgent,
										GroupLayout.DEFAULT_SIZE,
										GroupLayout.DEFAULT_SIZE,
										Short.MAX_VALUE)));

		layout.setAutoCreateGaps(true);
		layout.setAutoCreateContainerGaps(true);

		mControl.registerListener(this);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("timer")) {
			mNumSecs++;
			mTime.setText(secsToTime(mNumSecs));
			return;
		}
		if (e.getActionCommand().equals("start")) {
			mControl.startLoop(mAgent);
			return;
		}
		if (e.getActionCommand().equals("stop")) {
			mControl.stopLoop();
			return;
		}
		if (e.getActionCommand().equals("new")) {
			mControl.newLabyrinth();
			return;
		}
		if (e.getActionCommand().equals("agent")) {
			JComboBox cb = (JComboBox) e.getSource();
			mAgent = (IAgent) cb.getSelectedItem();
			return;
		}
		if (e.getActionCommand().equals("add")) {
			JFileChooser agentFileChooser = new JFileChooser();
			int returnVal = agentFileChooser.showOpenDialog(this);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File agentFile = agentFileChooser.getSelectedFile();
				addAgent(agentFile.getAbsolutePath());
			}
		}
		if (e.getActionCommand().equals("rm")) {
			mControl.unregisterAgent(mAgent);
			updateAgentList();
		}

	}

	/**
	 * Formats a number to a clock-like string: hh:mm:ss.cs
	 * 
	 * @param numSecs
	 *            The number to format
	 * @return A string in the clock-like format
	 */
	private String secsToTime(long numSecs) {
		long hs, s, min, h;
		hs = numSecs % 10;
		numSecs /= 10;
		s = numSecs % 60;
		numSecs /= 60;
		min = numSecs % 60;
		numSecs /= 60;
		h = numSecs % 60;
		String time = (h < 10 ? "0" : "") + h + ":" + (min < 10 ? "0" : "")
				+ min + ":" + (s < 10 ? "0" : "") + s + "." + hs;
		return time;
	}

	@Override
	public void arrived() {
		mTimer.stop();
	}

	@Override
	public void incrementSteps() {
		mNumSteps++;
		mSteps.setText(new Long(mNumSteps).toString());
	}

	@Override
	public void started() {
		mTimer = new Timer(100, this);
		mTimer.setActionCommand("timer");
		mTimer.start();
		mNumSteps = 0;
		mSteps.setText(new Long(mNumSteps).toString());
		mNumSecs = 0;
		mTime.setText(secsToTime(mNumSecs));
	}

	@Override
	public void stopped() {
		mTimer.stop();
	}

	/**
	 * Loads a agent class from a JAR
	 * 
	 * @param filename
	 *            the filename of the JAR
	 */
	private void addAgent(String filename) {
		IAgent newAgent = null;
		try {
			URLClassLoader agentloader = new URLClassLoader(
					new URL[] { new URL("file://" + filename) });
			String[] tmp = filename.split(System.getProperty("file.separator"));
			String classname = tmp[tmp.length - 1];
			classname = classname.substring(0, classname.length() - 4);
			System.out.println(classname);
			Class<?> agentClass = agentloader.loadClass(classname);
			newAgent = (IAgent) agentClass.newInstance();

		} catch (Exception e) {
			// error message for the user
			JOptionPane
					.showMessageDialog(
							this,
							"Die gewählte Datei konnte nicht geladen werden oder enthielt keinen gültigen Agenten.",
							"Fehler", JOptionPane.ERROR_MESSAGE);
			return;
		}
		mControl.registerAgent(newAgent);
		updateAgentList();
		JOptionPane
		.showMessageDialog(this, "Der Agent " + newAgent
				+ " wurde geladen.", "Geladen",
				JOptionPane.INFORMATION_MESSAGE);

	}

	public void updateAgentList() {
		mAgentsBox.setModel(new DefaultComboBoxModel(mControl
				.getPossibleAgents().toArray()));
		mAgent = (IAgent) mAgentsBox.getSelectedItem();
	}
}
